package wxpay

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

// WxPayService 微信支付服务
type WxPayService struct {
	AppID     string
	MchID     string
	APIKey    string
	NotifyURL string
	Client    *http.Client
}

// NewWxPayService 创建微信支付服务实例
func NewWxPayService(appID, mchID, apiKey, notifyURL string) *WxPayService {
	return &WxPayService{
		AppID:     appID,
		MchID:     mchID,
		APIKey:    apiKey,
		NotifyURL: notifyURL,
		Client:    &http.Client{Timeout: 10 * time.Second},
	}
}

// UnifiedOrder 统一下单
func (s *WxPayService) UnifiedOrder(req *UnifiedOrderRequest) (*UnifiedOrderResponse, error) {
	// 1. 准备请求参数
	params := map[string]string{
		"appid":            s.AppID,
		"mch_id":           s.MchID,
		"nonce_str":        GenerateNonceStr(),
		"body":             req.Body,
		"out_trade_no":     req.OutTradeNo,
		"total_fee":        req.TotalFee,
		"spbill_create_ip": req.SpbillCreateIP,
		"notify_url":       s.NotifyURL,
		"trade_type":       req.TradeType,
		"openid":           req.OpenID,
		"attach":           req.Attach,
	}

	// 2. 生成签名
	params["sign"] = GenerateSign(params, s.APIKey)

	// 3. 转换为XML
	xmlStr, err := MapToXML(params)
	if err != nil {
		return nil, fmt.Errorf("生成XML失败: %v", err)
	}

	// 4. 发送请求
	resp, err := s.Client.Post("https://api.mch.weixin.qq.com/pay/unifiedorder", "application/xml", bytes.NewBufferString(xmlStr))
	if err != nil {
		return nil, fmt.Errorf("请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 5. 读取响应
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %v", err)
	}

	// 6. 解析响应
	var result UnifiedOrderResponse
	err = xml.Unmarshal(body, &result)
	if err != nil {
		return nil, fmt.Errorf("解析响应失败: %v", err)
	}

	// 7. 验证签名
	params, err = XMLToMap(string(body))
	if err != nil {
		return nil, fmt.Errorf("解析响应XML失败: %v", err)
	}
	if !VerifySign(params, s.APIKey) {
		return nil, fmt.Errorf("签名验证失败")
	}

	return &result, nil
}

// HandlePayNotify 处理支付结果通知
func (s *WxPayService) HandlePayNotify(body []byte) (*PayNotifyRequest, *PayNotifyResponse, error) {
	// 1. 解析通知数据
	var notifyReq PayNotifyRequest
	err := xml.Unmarshal(body, &notifyReq)
	if err != nil {
		return nil, nil, fmt.Errorf("解析通知数据失败: %v", err)
	}

	// 2. 验证签名
	params, err := XMLToMap(string(body))
	if err != nil {
		return nil, nil, fmt.Errorf("解析通知XML失败: %v", err)
	}
	if !VerifySign(params, s.APIKey) {
		return nil, nil, fmt.Errorf("签名验证失败")
	}

	// 3. 准备响应
	resp := &PayNotifyResponse{
		ReturnCode: "SUCCESS",
		ReturnMsg:  "OK",
	}

	return &notifyReq, resp, nil
}
